package com.zengde.ai_sandbox.aspect;

import com.zengde.ai_sandbox.annonation.LogAround;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.Arrays;

@Aspect  // 声明这是一个切面，告诉Spring你是那个“工人”
@Component // 同时也要是一个Spring管理的Bean，工人得持证上岗
public class LoggingAspect {

    // @Around 注解定义了工人要在什么时候出现。
    // 参数 "@annotation(logAround)" 是触发条件：只要方法上贴了@LogAround注解，就拦截它。
    // 参数 LogAround logAround：这让你能拿到注解本身的属性值（比如上面的value）
    @Around("@annotation(logAround)")
    public Object logAround(ProceedingJoinPoint joinPoint, LogAround logAround) throws Throwable {

        // 1. 获取方法签名和方法名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getName();

        // 2. 【关键点：获取入参】
        // joinPoint.getArgs() 返回的是被拦截方法的参数列表（一个数组）
        Object[] args = joinPoint.getArgs();
        // 把参数数组打印成易读的字符串
        String inputParams = Arrays.toString(args);

        // 打印方法开始日志，包含入参
        System.out.println("【方法开始】: " + methodName + " | 入参: " + inputParams + " | 注解备注: " + logAround.value());

        // 3. 执行目标方法（相当于让箱子继续在流水线上走下去）
        // proceed() 方法的作用就是执行被拦截的那个原始方法。
        // 它的返回值就是原始方法的返回值。
        Object result;
        try {
            result = joinPoint.proceed(); // 这一行就是执行原方法
        } catch (Throwable throwable) {
            // 如果方法抛出异常，在这里也能捕获到
            System.out.println("【方法异常】: " + methodName + " | 异常: " + throwable.getMessage());
            throw throwable; // 记得重新抛出异常，不要吞掉它
        }

        // 4. 打印方法结束日志，包含出参（返回值）
        System.out.println("【方法结束】: " + methodName + " | 出参: " + result);

        // 5. 将原方法的返回值返回，否则调用方会收到null
        return result;
    }
}